
#include <memory>

#include <windows.h>

#include <QAxObject>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>

#include "ExcelHelp.h"
#include "pugixml.hpp"

void writeCSVFile(QFile &file, const QList<QStringList> &content)
{
    QTextStream stream(&file);

    for (int r = 0; r < content.size(); r++)
    {
        const auto &rowlist = content[r];
        for (int c = 0; c < rowlist.size(); c++)
        {
            const QString &str = rowlist[c];
            stream << str;
            if (c < rowlist.size() - 1)
            {
                stream << ",";
            }
        }
        stream << "\n";
    }
}

void readCSVFile(QFile &file, QList<QStringList> &content)
{
    QTextStream stream(&file);
    while (!stream.atEnd())
    {
        QString line = stream.readLine();
        QStringList rowlist = line.split(",");
        content.append(rowlist);
    }
}

bool writeXmlFile(const QString &filename,           //
                  const QList<QStringList> &content, //
                  int rows,                          //
                  int cols                           //
)
{
    pugi::xml_document doc;
    pugi::xml_node workbook = doc.append_child("Workbook");

    pugi::xml_node worksheet = workbook.append_child("Worksheet");
    worksheet.append_attribute("ss:Name").set_value("Sheet1");

    pugi::xml_node table = worksheet.append_child("Table");

    for (const QStringList &row : content)
    {
        pugi::xml_node xmlRow = table.append_child("Row");
        for (const QString &value : row)
        {
            pugi::xml_node cell = xmlRow.append_child("Cell");
            cell.append_child("Data").text().set(value.toStdString().c_str());
        }
    }

    auto localfilename = filename.toLocal8Bit().toStdString();

    // 保存XML文档为Excel文件
    bool ok = doc.save_file(localfilename.c_str(),                      //
                            "\t",                                       //
                            pugi::format_default | pugi::format_indent, //
                            pugi::xml_encoding::encoding_utf8);
    return ok;
}

bool writeXLSXFile(const QString &filename,     //
                   const QVariantList &content, //
                   int rows,                    //
                   int cols,                    //
                   QColor bgcolor)
{
    using AxObject = std::shared_ptr<QAxObject>;
    AxObject excel = AxObject(new QAxObject("Excel.Application"));
    if (excel->isNull())
    {
        QMessageBox::critical(nullptr,                                                  //
                              QObject::tr("错误"),                                      //
                              QObject::tr("系统没有安装《Microsoft Office》或《WPS》"), //
                              QMessageBox::Ok);
        return false;
    }
    {
        QString doc = excel->generateDocumentation();
        QFile outFile("Excel.Application.html");
        outFile.open(QIODevice::WriteOnly | QIODevice::Append);
        QTextStream ts(&outFile);
        ts << doc << endl;
        outFile.close();
    }

    bool exception = false;
    AxObject workbooks;
    AxObject workbook;
    try
    {
        excel->setProperty("Visible", IsDebuggerPresent());
        excel->setProperty("DisplayAlerts", false);
        workbooks = AxObject(excel->querySubObject("Workbooks"));
        workbook = AxObject(workbooks->querySubObject("Add"));
        if (rows > 0 && cols > 0)
        {
            AxObject sheets = AxObject(workbook->querySubObject("Sheets"));
            AxObject sheet = AxObject(sheets->querySubObject("Item(int)", 1));
            AxObject cellTopLeft = AxObject(sheet->querySubObject("Cells(int,int)", 1, 1));
            AxObject cellBottomRight = AxObject(sheet->querySubObject("Cells(int,int)", //
                                                                      rows,             //
                                                                      cols));

            AxObject range = AxObject(sheet->querySubObject("Range(const QVariant&,const QVariant&)", //
                                                            QVariant::fromValue(cellTopLeft.get()),   //
                                                            QVariant::fromValue(cellBottomRight.get())));

            AxObject interior = AxObject(range->querySubObject("Interior"));
            if (!interior->isNull())
            {
                interior->setProperty("Color", bgcolor);
            }

            range->dynamicCall("SetValue(const QVariant&)", content);
        }
    }
    catch (const std::exception &)
    {
        exception = true;
    }
    catch (...)
    {
        exception = true;
    }

    if (workbook && !workbook->isNull())
    {
        workbook->dynamicCall("SaveAs(const QString&)", filename);
        workbook->dynamicCall("Close(bool)", false);
    }
    workbook.reset();
    workbooks.reset();
    excel->dynamicCall("Quit()");

    if (exception)
    {
        return false;
    }

    return true;
}

bool readXLSXFile(const QString &filename, //
                  QVariantList &content,   //
                  int rows,                //
                  int cols                 //
)
{
    content.clear();
    using AxObject = std::shared_ptr<QAxObject>;
    AxObject excel = AxObject(new QAxObject("Excel.Application"));
    if (excel->isNull())
    {
        QMessageBox::critical(nullptr,                                                  //
                              QObject::tr("错误"),                                      //
                              QObject::tr("系统没有安装《Microsoft Office》或《WPS》"), //
                              QMessageBox::Ok);
        return false;
    }

    bool exception = false;
    AxObject workbooks;
    AxObject workbook;

    try
    {
        excel->setProperty("Visible", IsDebuggerPresent());
        workbooks = AxObject(excel->querySubObject("Workbooks"));
        workbook = AxObject(workbooks->querySubObject("Open(const QString&)", filename));
        AxObject sheets = AxObject(workbook->querySubObject("Sheets"));
        AxObject sheet = AxObject(sheets->querySubObject("Item(int)", 1));

        AxObject range;
        if (rows > 0 && cols > 0)
        {
            AxObject cellTopLeft = AxObject(sheet->querySubObject("Cells(int,int)", 1, 1));
            AxObject cellBottomRight = AxObject(sheet->querySubObject("Cells(int,int)", //
                                                                      rows,             //
                                                                      cols));

            AxObject range = AxObject(sheet->querySubObject("Range(const QVariant&,const QVariant&)", //
                                                            cellTopLeft->asVariant(),                 //
                                                            cellBottomRight->asVariant()));
        }
        else
        {
            range = AxObject(sheet->querySubObject("UsedRange"));
        }

        content = range->dynamicCall("Value()").toList();
    }
    catch (const std::exception &)
    {
        exception = true;
    }
    catch (...)
    {
        exception = true;
    }

    if (workbook && !workbook->isNull())
    {
        workbook->dynamicCall("Close(bool)", false);
    }
    workbook.reset();
    workbooks.reset();
    excel->dynamicCall("Quit()");

    if (exception)
    {
        return false;
    }

    return true;
}